package es

import (
    "context"
    "encoding/json"
    "github.com/olivere/elastic/v7"
    "strings"
)

var host = "http://127.0.0.1:9200"

// GetEsClient 获取 es 实例
func GetEsClient() (client *elastic.Client) {
    var err error
    // 初始化客户端
    client, err = elastic.NewClient(
        elastic.SetSniff(false),
        elastic.SetURL(host),
    )
    if err != nil {
        panic(err)
    }
    // 连接服务测试
    _, _, err = client.Ping(host).Do(context.Background())
    if err != nil {
        panic(err)
    }
    return client
}

// IsExist 判断索引是否存在
func IsExist(index string) bool {
    client := GetEsClient()
    exist, err := client.IndexExists(index).Do(context.Background())
    if err != nil {
        panic(err)
    }
    return exist
}

// CreateIndex 创建索引
func CreateIndex(index string) bool {
    client := GetEsClient()
    res, err := client.CreateIndex(index).IncludeTypeName(true).Do(context.Background())
    if err != nil {
        panic(err)
    }
    return res.Acknowledged
}

// DelIndex 删除索引
func DelIndex(index string) bool {
    client := GetEsClient()
    res, err := client.DeleteIndex(index).Do(context.Background())
    if err != nil {
        panic(err)
    }
    return res.Acknowledged
}

// GetData 获取 es 单条数据
func GetData(index string, id string) string {
    client := GetEsClient()
    res, err := client.Get().Index(index).Id(id).Do(context.Background())
    if err != nil {
        panic(err)
    }
    jsonStr, err := json.Marshal(res.Source)
    if err != nil {
        panic(err)
    }
    //res, err := client.Search(index).From((page - 1) * size).Size(size).Pretty(true).Do(context.Background())
    return string(jsonStr)
}

// FlushEs 刷新 es 数据
func FlushEs(index string) bool {
    client := GetEsClient()
    res, err := client.Flush(index).Do(context.Background())
    if err != nil {
        panic(err)
    }
    return res.Shards.Successful > 0
}

// GetList 获取 es 数据列表
// index：es索引名称,
// where：查询条件,
// page：分页页数,
// size：每页多少条,
// sort：排序, 可以按多字段排序
func GetList(index string, where map[string]map[string]interface{}, page int, size int, sort map[string]interface{}) (list []map[string]interface{}, count int64) {
    client := GetEsClient()
    from := (page - 1) * size
    boolq := getWhere(where)
    service := client.Search(index).Query(boolq).From(from).Size(size)
    for k, v := range sort {
        sortQuery := elastic.NewFieldSort(k)
        if strings.ToLower(v.(string)) == "desc" {
            sortQuery.Desc()
        }
        service.SortBy(sortQuery)
    }
    res, err := service.Do(context.Background())
    if err != nil {
        panic(err)
    }
    count = res.TotalHits()
    hits := res.Hits.Hits
    for _, hit := range hits {
        var t map[string]interface{}
        json.Unmarshal(hit.Source, &t)
        list = append(list, t)
    }
    return list, count
}

// Add 添加 es 数据
// index：es 索引，
// id：要添加的数据 id，
// body：要添加的数据
func Add(index string, id string, body interface{}) (bool, error) {
    client := GetEsClient()
    res, err := client.Index().Index(index).Id(id).BodyJson(body).Do(context.Background())
    if err != nil {
        return false, err
    }
    return res.Result == "created", nil
}

// DelById 根据 id 删除 es 数据
// index：es 索引，
// id：要删除的数据 id
func DelById(index string, id string) (bool, error) {
    client := GetEsClient()
    res, err := client.Delete().Index(index).Id(id).Do(context.Background())
    if err != nil {
        return false, err
    }
    return res.Result == "deleted", nil
}

// DelByWhere 根据条件删除 es 数据
// index：es 索引，
// where：条件
func DelByWhere(index string, where map[string]map[string]interface{}) (int64, error) {
    client := GetEsClient()
    boolq := getWhere(where)
    res, err := client.DeleteByQuery(index).Query(boolq).Refresh("true").Do(context.Background())
    if err != nil {
        return 0, err
    }
    return res.Deleted, nil
}

// ModifyById 根据 id 修改 es 数据
// index：es 索引，
// id：要修改的数据 id，
// data：要修改的新数据
func ModifyById(index string, id string, data map[string]interface{}) (bool, error) {
    client := GetEsClient()
    res, err := client.Update().Index(index).Id(id).Doc(data).Do(context.Background())
    if err != nil {
        return false, err
    }
    return res.Result == "updated", nil
}

// ModifyByWhere 根据条件修改数据
// index：es 索引，
// where：条件，
// data：脚本指定待更新的字段与值
func ModifyByWhere(index string, where map[string]map[string]interface{}, data map[string]interface{}) (int64, error) {
    client := GetEsClient()
    boolq := getWhere(where)
    script := elastic.Script{}
    script.Params(data)
    res, err := client.UpdateByQuery(index).Query(boolq).Script(&script).Refresh("true").Do(context.Background())
    if err != nil {
        return 0, err
    }
    return res.Updated, nil
}

// 组装where条件
func getWhere(where map[string]map[string]interface{}) *elastic.BoolQuery {
    boolq := elastic.NewBoolQuery()
    for k1, v1 := range where {
        for k, v := range v1 {
            if k1 == "=" || k1 == "eq" {
                boolq.Must(elastic.NewTermQuery(k, v))
            } else if k1 == ">" || k1 == "gt" {
                boolq.Filter(elastic.NewRangeQuery(k).Gt(v))
            } else if k1 == ">=" || k1 == "gte" {
                boolq.Filter(elastic.NewRangeQuery(k).Gte(v))
            } else if k1 == "<" || k1 == "lt" {
                boolq.Filter(elastic.NewRangeQuery(k).Lt(v))
            } else if k1 == "<=" || k1 == "lte" {
                boolq.Filter(elastic.NewRangeQuery(k).Lte(v))
            } else if k1 == "like" {
                boolq.Filter(elastic.NewWildcardQuery(k, "*"+v.(string)+"*"))
            } else if k1 == "or" {
                fields := strings.Split(k, "|")
                for _, field := range fields {
                    term := elastic.NewTermQuery(field, v)
                    boolq.Should(term)
                }
            }
        }
    }
    return boolq
}